home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 21
/
Cream of the Crop 21 (Terry Blount) (October 1996).iso
/
program
/
libkb100.zip
/
LIBKB-1.00
/
SRC
/
KBSIGNAL.C
< prev
next >
Wrap
C/C++ Source or Header
|
1996-07-23
|
12KB
|
571 lines
/* kbsignal.c -- signal handling
* Copyright (C) 1995, 1996 Markus F.X.J. Oberhumer
* For conditions of distribution and use, see copyright notice in kb.h
*/
#include <signal.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <kb.h>
#include "_kb.h"
#if defined(KB_LOCK_ALL_START)
KB_LOCK_ALL_START(_libkb_kbsignal)
#endif
/***********************************************************************
// wrapper for djgpp v1
************************************************************************/
#if defined(_KB_NO_SIGNALS)
const int _kb_nsig = 0;
const int _kb_sigmin = 0;
const int _kb_sigmax = -1;
#if !defined(SIG_ERR)
# define SIG_ERR NULL
#endif
int _kb_signal_install(void)
{
return 0; /* installation ok */
}
static void _my_signal_handler(int signum)
{
_kb_emergency_remove(1);
exit(EXIT_SIG(signum));
}
const kb_sighandler_t kb_signal_handler = _my_signal_handler;
kb_sighandler_t kb_signal(int signum, kb_sighandler_t handler)
{
return SIG_ERR;
}
kb_sighandler_t kb_get_chained_signal(int signum)
{
return SIG_ERR;
}
kb_sighandler_t kb_set_chained_signal(int signum, kb_sighandler_t h)
{
return SIG_ERR;
}
#endif /* _KB_NO_SIGNALS */
/***********************************************************************
// IMPORTANT NOTE: check your compiler flags so that no
// stack overflow checks will be inserted here !
************************************************************************/
#if !defined(_KB_NO_SIGNALS)
/* don't waste memory */
#if defined(__DJGPP__)
# define KB_SIGMIN 288
#else
# define KB_SIGMIN 0
#endif
/* NSIG is the highest defined signal number + 1 */
#if !defined(NSIG)
# if defined(_NSIG)
# define NSIG _NSIG
# elif defined(SIGMAX)
# define NSIG (SIGMAX+1)
# elif defined(_SIGMAX)
# define NSIG (_SIGMAX+1)
# else
# define NSIG (32 + KB_SIGMIN)
# endif
#endif
const int _kb_nsig = NSIG;
const int _kb_sigmin = KB_SIGMIN;
const int _kb_sigmax = NSIG - 1;
/* sigaction() gives us more control than signal() */
#if defined(__KB_LINUX)
# define _KB_USE_SIGACTION_GET
#elif defined(__EMX__)
# define _KB_USE_SIGACTION_GET
# define _KB_USE_SIGACTION_SET
#endif
/***********************************************************************
// wrappers for sigaction/signal
************************************************************************/
#if defined(_KB_USE_SIGACTION_GET)
static kb_sighandler_t kb_signal_get_sa(int signum, struct sigaction *sa)
{
if (sa == NULL)
return SIG_ERR;
if (sigaction(signum,NULL,sa) != 0)
return SIG_ERR;
return sa->sa_handler;
}
#endif
#if defined(_KB_USE_SIGACTION_SET)
static kb_sighandler_t kb_signal_set_sa(int signum, kb_sighandler_t h,
struct sigaction *sa)
{
kb_sighandler_t oldh;
if (sa == NULL)
return SIG_ERR;
if (sigaction(signum,NULL,sa) != 0)
return SIG_ERR;
oldh = sa->sa_handler;
if (oldh == SIG_ERR || h == SIG_ERR)
return SIG_ERR;
sa->sa_handler = h;
#if defined(__EMX__) /* use the emx signal processing model */
sa->sa_flags &= ~(SA_SYSV);
sa->sa_flags |= (SA_ACK);
#endif
if (sigaction(signum,sa,NULL) != 0)
return SIG_ERR;
return oldh;
}
#endif
static kb_sighandler_t kb_signal_get(int signum)
{
#if defined(_KB_USE_SIGACTION_GET)
struct sigaction sa;
return kb_signal_get_sa(signum,&sa);
#else
kb_sighandler_t h;
h = signal(signum,SIG_DFL); /* get and set handler */
if (h == SIG_ERR) /* error in signal() call */
return SIG_ERR;
if (h != SIG_DFL)
if (signal(signum,h) == SIG_ERR) /* restore handler */
return SIG_ERR;
return h;
#endif
}
static kb_sighandler_t kb_signal_set(int signum, kb_sighandler_t h)
{
#if defined(_KB_USE_SIGACTION_SET)
struct sigaction sa;
return kb_signal_set_sa(signum,h,&sa);
#else
return signal(signum,h);
#endif
}
/***********************************************************************
// vars for the old (chained) signal handlers
************************************************************************/
/* don't waste memory */
#define old_sigh (__old_sigh - KB_SIGMIN)
#define sig_installed (__sig_installed - KB_SIGMIN)
#if defined(_KB_USE_SIGACTION_GET)
static struct sigaction __old_sigh[NSIG - KB_SIGMIN];
# define OLD_SIGH(signum) (old_sigh[signum].sa_handler)
#else
static kb_sighandler_t __old_sigh[NSIG - KB_SIGMIN];
# define OLD_SIGH(signum) (old_sigh[signum])
#endif
static unsigned char __sig_installed[NSIG - KB_SIGMIN];
/***********************************************************************
// our signal handler
************************************************************************/
static void _my_signal_handler(int signum)
{
int err;
#if defined(KB_DEBUG) && (KB_DEBUG >= 2)
/* remove keyboard handler before doing anything else */
_kb_emergency_remove(0);
/* file I/O is somewhat dangerous within a signal handler ... */
fprintf(stderr,"libkb: received signal %d%s\n", signum,
(signum < KB_SIGMIN || signum >= NSIG) ? " STRANGE !!!" : "");
fflush(stderr);
#endif
/* remove keyboard handler */
_kb_emergency_remove(1);
/* sanity check */
if (signum < KB_SIGMIN || signum >= NSIG)
return;
/* restore old signal handler */
if (sig_installed[signum] != 0x01) /* should not happen */
{
err = (signal(signum,SIG_DFL) == SIG_ERR);
#if defined(KB_DEBUG) && (KB_DEBUG >= 2)
fprintf(stderr,"libkb: signal %d not expected !!!\n", signum);
fflush(stderr);
#endif
}
#if defined(_KB_USE_SIGACTION_GET)
else if (sigaction(signum,&old_sigh[signum],NULL) != 0)
err = 1;
#else
else if (signal(signum,old_sigh[signum]) == SIG_ERR)
err = 1;
#endif
else
err = 0;
#if defined(__EMX__) /* emx signal processing model */
signal(signum,SIG_ACK); /* ack. signal */
#endif
/* chain old signal handler - this should terminate the program */
if (!err)
{
sig_installed[signum] = 0; /* no longer active */
#if defined(KB_DEBUG) && (KB_DEBUG >= 2)
fprintf(stderr,"libkb: chaining signal %d\n",signum);
fflush(stderr);
#endif
raise(signum);
}
/* if we return from here, the application should be aware
* that the keyboard handler was removed.
*/
}
/* improve source code readability (at least a little bit :-) */
#define MY_HANDLER _my_signal_handler
/* make accessible */
const kb_sighandler_t kb_signal_handler = MY_HANDLER;
/***********************************************************************
// install a signal handler (compatible to signal())
************************************************************************/
kb_sighandler_t kb_signal(int signum, kb_sighandler_t handler)
{
kb_sighandler_t h;
if (signum < KB_SIGMIN || signum >= NSIG || handler == SIG_ERR)
return SIG_ERR;
h = kb_signal_get(signum);
if (h == SIG_ERR)
{
sig_installed[signum] = 0x81;
return SIG_ERR;
}
if (h == MY_HANDLER && sig_installed[signum] != 0x01)
{
/* strange: someone installed my handler without my knowledge */
sig_installed[signum] = 0x01;
}
if (h == handler) /* no change */
return h;
if (handler != MY_HANDLER) /* not my handler */
{
if (kb_signal_set(signum,handler) != h)
return SIG_ERR;
if (handler == SIG_IGN)
sig_installed[signum] = 0x20;
else
sig_installed[signum] = 0x10;
return h;
}
/* are you still here ? :-) */
/* assert(handler == MY_HANDLER); */
/* store current signal information */
#if defined(_KB_USE_SIGACTION_GET)
if (kb_signal_get_sa(signum,&old_sigh[signum]) != h)
return SIG_ERR;
#else
old_sigh[signum] = h;
#endif
/* if the signal is ignored, we ignore it as well */
if (h == SIG_IGN)
{
sig_installed[signum] = 0x02;
return h;
}
/* now the time has come to install our handler */
if (kb_signal_set(signum,handler) != h)
{
sig_installed[signum] = 0x82;
return SIG_ERR;
}
/* everything ok */
sig_installed[signum] = 0x01;
return h;
}
/***********************************************************************
// install all signal handlers
// note: a handler cannot be installed for SIGKILL, so
// don't "kill -9" as this will not restore the keyboard
************************************************************************/
/* FIXME: which signals ? */
/* We catch all signals that cause an exit by default (aka almo